package com.qding.park.manager.service.statis.util;


/**
 * @Title: BsonUtil.java
 * @Package com.qding.smart.common.utils
 * @Description: TODO
 * Copyright: Copyright (c) 2011 
 * Company:千丁互联
 * 
 * @author Comsys-Administrator
 * @date 2016年7月10日 下午4:02:38
 * @version V1.0
 */

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.bson.Document;
import org.bson.types.ObjectId;

import com.mongodb.BasicDBObject;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;

/*
 * 将mongo的文档转化为对象将对象转化为mongo文档
 * @author:maybo
 * @data:2016-2-1
 */
public class BsonUtil {
	public static <T> List<T> toBeans(List<Document> documents, Class<T> clazz)
			throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
		List<T> list = new ArrayList<T>();
		for (int i = 0; null != documents && i < documents.size(); i++) {
			list.add(toBean(documents.get(i), clazz));
		}
		return list;
	}

	/*
	 * 将Bson 转化为对象
	 * 
	 * @param:Bson文档
	 * 
	 * @param:类pojo
	 * 
	 * @param:返回对象
	 */
	public static <T> T toBean(Document document, Class<T> clazz) {
		// throws InstantiationException, IllegalAccessException,
		// IllegalArgumentException, InvocationTargetException {
		try {
			T obj = clazz.newInstance();// 声明一个对象
			Field[] fields = clazz.getDeclaredFields();// 获取所有属性
			Method[] methods = clazz.getMethods();// 获取所有的方法
			/*
			 * 查找所有的属性，并通过属性名和数据库字段名通过相等映射
			 */
			for (int i = 0; i < fields.length; i++) {
				String fieldName = fields[i].getName();
				Object bson = null;
				 if ("id".equals(fieldName)) {

					Object _idObj = document.get("_id") == null ? null : document.get("_id");
					if (_idObj != null && _idObj instanceof ObjectId) {

						bson = ((ObjectId) _idObj).toHexString();
					} else if (_idObj != null && _idObj instanceof String) {
						bson = _idObj;
					} else {
						bson = null;
					}
					// bson = document.get("_id");

				} else {
					bson = document.get(fieldName);
				}
				if (null == bson) {
					continue;
				} else if (bson instanceof Document) {// 如果字段是文档了递归调用
					bson = toBean((Document) bson, fields[i].getType());
				} else if (bson instanceof MongoCollection) {// 如果字段是文档集了调用colTOList方法

					bson = colToList(bson, fields[i]);
				} else if (bson instanceof List) {
					bson = colToList_v2(bson, fields[i]);
				}
				fields[i].setAccessible(true);
				fields[i].set(obj, bson);
				// for (int j = 0; j < methods.length; j++) {// 为对象赋值
				// String metdName = methods[j].getName();
				// if (equalFieldAndSet(fieldName, metdName)) {
				// methods[j].invoke(obj, bson);
				// break;
				// }
				// }
			}
			return obj;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	
	public static <T> T toBean(BasicDBObject document, Class<T> clazz) {
		// throws InstantiationException, IllegalAccessException,
		// IllegalArgumentException, InvocationTargetException {
		try {
			T obj = clazz.newInstance();// 声明一个对象
			Field[] fields = clazz.getDeclaredFields();// 获取所有属性
			Method[] methods = clazz.getMethods();// 获取所有的方法
			/*
			 * 查找所有的属性，并通过属性名和数据库字段名通过相等映射
			 */
			for (int i = 0; i < fields.length; i++) {
				String fieldName = fields[i].getName();
//				Column column = fields[i].getAnnotation(Column.class);
				Object bson = null;
				if ("id".equals(fieldName)) {

					Object _idObj = document.get("_id") == null ? null : document.get("_id");
					if (_idObj != null && _idObj instanceof ObjectId) {

						bson = ((ObjectId) _idObj).toHexString();
					} else if (_idObj != null && _idObj instanceof String) {
						bson = _idObj;
					} else {
						bson = null;
					}
					// bson = document.get("_id");

				} else {
					bson = document.get(fieldName);
				}
				if (null == bson) {
					continue;
				} else if (bson instanceof Document) {// 如果字段是文档了递归调用
					bson = toBean((Document) bson, fields[i].getType());
				} else if (bson instanceof MongoCollection) {// 如果字段是文档集了调用colTOList方法

					bson = colToList(bson, fields[i]);
				} else if (bson instanceof List) {
					bson = colToList_v2(bson, fields[i]);
				}
				fields[i].setAccessible(true);
				fields[i].set(obj, bson);
				// for (int j = 0; j < methods.length; j++) {// 为对象赋值
				// String metdName = methods[j].getName();
				// if (equalFieldAndSet(fieldName, metdName)) {
				// methods[j].invoke(obj, bson);
				// break;
				// }
				// }
			}
			return obj;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static List<Document> toBsons(List<Object> objs) throws IllegalArgumentException, SecurityException,
			IllegalAccessException, InvocationTargetException, NoSuchFieldException {
		List<Document> documents = new ArrayList<Document>();
		for (int i = 0; null != objs && i < objs.size(); i++) {
			documents.add(toBson(objs.get(i)));
		}
		return documents;
	}

	/*
	 * 将对象转化为Bson文档
	 * 
	 * @param:对象
	 * 
	 * @param:类型
	 * 
	 * @return:文档
	 */
	public static Document toBson(Object obj) {
		try {
			if (null == obj) {
				return null;
			}
			Class<? extends Object> clazz = obj.getClass();
			Document document = new Document();
			Method[] methods = clazz.getDeclaredMethods();
			Field[] fields = clazz.getDeclaredFields();
			for (int i = 0; null != fields && i < fields.length; i++) {
//				Column column = fields[i].getAnnotation(Column.class);// 获取列注解内容
//				NotColumn notColumn = fields[i].getAnnotation(NotColumn.class);// 获取否列
				String key = null;// 对应的文档键值
//				if (null != column && null != column.name()) {// 存在列映射取值
//					key = column.name();
//				} else if (null != notColumn) {// 不是列的情况
//					continue;
//				} else {
					key = fields[i].getName();// 默认情况通过属性名映射
					if ("id".equals(key)) {// 替换id为_id
						key = "_id";
					}
//				}
				String fieldName = fields[i].getName();
				if ("associatedFault".equals(fieldName)) {
					System.out.println("");
				}
				/*
				 * 获取对象属性值并映射到Document中
				 */
				for (int j = 0; null != methods && j < methods.length; j++) {
					String methdName = methods[j].getName();
					if (null != fieldName && equalFieldAndGet(fieldName, methdName)) {
						Object val = methods[j].invoke(obj);// 得到值
						if (null == val) {
							continue;
						}
						if (isJavaClass(methods[j].getReturnType())) {
							Type fc = methods[j].getGenericReturnType();
							if (methods[j].getReturnType().getName().equals("java.util.List")) {// 列表处理
								@SuppressWarnings("unchecked")
								List<Object> list = (List<Object>) val;
								// List<Document> documents = new
								// ArrayList<Document>();
								List<Object> documents = new ArrayList<Object>();
								if (fc == null || !(fc instanceof ParameterizedType)) {
									// 如果不是泛型
									for (Object obj1 : list) {
										documents.add(toBson(obj1));
									}
								} else if (fc instanceof ParameterizedType) {
									// 如果是泛型
									ParameterizedType pt = (ParameterizedType) fc;
									Class genericClazz = (Class) pt.getActualTypeArguments()[0];
									if (isJavaClass(genericClazz)) {
										// 是基本数据类型
										for (Object obj1 : list) {
											documents.add(obj1);
										}
									} else {
										for (Object obj1 : list) {
											documents.add(toBson(obj1));
										}
									}
								}

								document.append(key, documents);
							} else if ("java.util.Set".equals(methods[j].getReturnType().getName())) {
								@SuppressWarnings("unchecked")
								Set<Object> set = (Set<Object>) val;
								// Set<Document> documents = new
								// HashSet<Document>();
								Set<Object> documents = new HashSet<Object>();
								if (fc == null || !(fc instanceof ParameterizedType)) {
									for (Object obj1 : set) {
										documents.add(toBson(obj1));
									}
								} else if (fc instanceof ParameterizedType) {
									// 如果是泛型
									ParameterizedType pt = (ParameterizedType) fc;
									Class genericClazz = (Class) pt.getActualTypeArguments()[0];
									if (isJavaClass(genericClazz)) {
										// 是基本数据类型
										for (Object obj1 : set) {
											documents.add(obj1);
										}
									} else {
										for (Object obj1 : set) {
											documents.add(toBson(obj1));
										}
									}
								}

								document.append(key, documents);
							} else {// 其它对象处理，基本类型
								document.append(key, val);
							}
						} else {// 自定义类型
							document.append(key, toBson(val));
						}
					}
				}
			}
			return document;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/*
	 * 是否是自定义类型】
	 * 
	 * false:是自定义
	 */
	private static boolean isJavaClass(Class<?> clz) {
		return clz != null && clz.getClassLoader() == null;
	}

	/*
	 * 将文档集转化为列表
	 * 
	 * @param:文档集
	 * 
	 * @param:属性类型
	 * 
	 * @return:返回列表
	 */
	private static List<Object> colToList(Object bson, Field field)
			throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		ParameterizedType pt = (ParameterizedType) field.getGenericType();// 获取列表的类型
		List<Object> objs = new ArrayList<Object>();
		@SuppressWarnings("unchecked")
		MongoCollection<Document> cols = (MongoCollection<Document>) bson;
		MongoCursor<Document> cursor = cols.find().iterator();
		while (cursor.hasNext()) {
			Document child = cursor.next();
			@SuppressWarnings("rawtypes")
			Class clz = (Class) pt.getActualTypeArguments()[0];// 获取元素类型
			@SuppressWarnings("unchecked")
			Object obj = toBean(child, clz);
			System.out.println(child);
			objs.add(obj);

		}
		return objs;
	}

	private static Collection<Object> colToList_v2(Object bson, Field field)
			throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		ParameterizedType pt = (ParameterizedType) field.getGenericType();// 获取列表的类型
		List<Object> objs = new ArrayList<Object>();
		if (pt == null) {
			// 不是泛型 按String list 处理
			if ("java.util.List".equals(field.getType().getName())) {
				// list
				return (List<Object>) bson;
			} else if ("java.util.Set".equals(field.getType().getName())) {
				List lis = (List<Object>) bson;
				Set<Object> setTemp = new HashSet<Object>(lis);
				return setTemp;
			}
			// @SuppressWarnings("unchecked")
			// MongoCollection<String> cols = (MongoCollection<String>) bson;
			// MongoCursor<String> cursor = cols.find().iterator();
			// while (cursor.hasNext()) {
			// String child = cursor.next();
			// @SuppressWarnings("rawtypes")
			// Class clz = (Class) pt.getActualTypeArguments()[0];// 获取元素类型
			// @SuppressWarnings("unchecked")
			// Object obj = toBean(child, clz);
			// System.out.println(child);
			// objs.add(obj);
			//
			// }

		} else {
			// 泛型
			Class genericClazz = (Class) pt.getActualTypeArguments()[0];
			if (isJavaClass(genericClazz)) {
				// 基本数据类型
				if ("java.util.List".equals(field.getType().getName())) {
					// list
					return (List<Object>) bson;
				} else if ("java.util.Set".equals(field.getType().getName())) {
					List lis = (List<Object>) bson;
					Set<Object> setTemp = new HashSet<Object>(lis);
					return setTemp;
				}

			} else {
				if ("java.util.List".equals(field.getType().getName())) {
					List<Object> objslist1 = new ArrayList<Object>();
					List<Document> cols = (List<Document>) bson;
					Iterator<Document> cursor = cols.iterator();
					while (cursor.hasNext()) {
						Document child = cursor.next();
						@SuppressWarnings("rawtypes")
						Class clz = genericClazz;// 获取元素类型
						@SuppressWarnings("unchecked")
						Object obj = toBean(child, clz);
						System.out.println(child);
						objslist1.add(obj);

					}
					return objslist1;
				} else if ("java.util.Set".equals(field.getType().getName())) {
					Set<Object> objsSet1 = new HashSet<Object>();
					List<Document> cols = (List<Document>) bson;
					Iterator<Document> cursor = cols.iterator();
					while (cursor.hasNext()) {
						Document child = cursor.next();
						@SuppressWarnings("rawtypes")
						Class clz = genericClazz;// 获取元素类型
						@SuppressWarnings("unchecked")
						Object obj = toBean(child, clz);
						System.out.println(child);
						objsSet1.add(obj);

					}
					return objsSet1;
				}
			}
		}

		return objs;
	}

	/*
	 * 比较setter方法和属性相等
	 */
	private static boolean equalFieldAndSet(String field, String name) {
		if (name.toLowerCase().matches("set" + field.toLowerCase())) {
			return true;
		} else {
			return false;
		}
	}

	/*
	 * 比较getter方法和属性相等
	 */
	private static boolean equalFieldAndGet(String field, String name) {
		if (name.toLowerCase().matches("get" + field.toLowerCase())) {
			return true;
		} else {
			return false;
		}
	}
}
